#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/err.h>

#define TRUE 1
#define FALSE 0

typedef unsigned char u8;
typedef int boolean;
typedef EVP_PKEY BigNum_t; // 这里我们使用 EVP_PKEY 结构来代表大数

// 错误处理函数
void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}

boolean X25519_algorithm(u8 mode, BigNum_t *point, BigNum_t *coef_k, EVP_PKEY *result)
{
    // EVP_PKEY_CTX *pctx;

    size_t len;
    boolean ret = FALSE;

    if (mode == 0)
    {
        EVP_PKEY_CTX *pctx;
        // 生成公钥
        /* Create the context for parameter generation */
        if (NULL == (pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL)))
            handleErrors();

        /* Generate the key */
        if (1 != EVP_PKEY_keygen_init(pctx))
            handleErrors();
        if (1 != EVP_PKEY_keygen(pctx, &result))
            handleErrors();
        else
        {
            ret = TRUE;
        }
        // 清理资源
        if (pctx)
            EVP_PKEY_CTX_free(pctx);
    }
    else if (mode == 1)
    {
        // 生成共享密钥
        if (!point || !coef_k)
        {
            fprintf(stderr, "Invalid input parameters.\n");
            return FALSE;
        }
        EVP_PKEY_CTX *kctx = NULL;
        kctx = EVP_PKEY_CTX_new(coef_k, NULL);// 初始化派生操作

        // 初始化派生上下文// 设置参数，例如对方的公钥
        if (!kctx || EVP_PKEY_derive_init(kctx) <= 0 || EVP_PKEY_derive_set_peer(kctx, point) <= 0)
        {
            handleErrors();
        }
        else
        {

            // 确定缓冲区长度
            if (EVP_PKEY_derive(kctx, NULL, &len) <= 0)
            {
                handleErrors();
            }
            u8 secret[32] = {0};

            // 生成共享密钥
            if (EVP_PKEY_derive(kctx, secret, &len) <= 0)
            {
                handleErrors();
            }
            else
            {
                // 假设 BigNum_t 结构有一个可以设置值的函数
                // 这里需要根据实际的 BigNum_t 结构来实现
                // SetBigNumValue(result, secret, len);
                ret = TRUE;
            }
            // OPENSSL_free(secret);
        }
        // 清理资源
        if (kctx)
            EVP_PKEY_CTX_free(kctx);
    }

    return ret;
}

// 你需要提供 BigNum_t 结构的实现和 SetBigNumValue 函数的实现
// 或者修改代码以适应你的 BigNum_t 结构。

int algo_25519_test()
{
    printf("algo_25519_test\n");
    // 这里是如何调用你的函数的例子
    EVP_PKEY *publicKey = NULL;
    BigNum_t *privateKey = NULL;
    BigNum_t *sharedSecret = NULL;

    u8 privateKeyData[32] = {0xc5, 0x58, 0xb4, 0x4b, 0xee, 0x53, 0x01, 0xd9, 0xf5, 0x2b, 0x44, 0xd9, 0x39, 0xbb, 0x59, 0x58,
                             0x4d, 0x75, 0xb9, 0x03, 0x4d, 0xd6, 0xa9, 0xfc, 0x82, 0x68, 0x72, 0x10, 0x9a, 0x65, 0x73, 0x9f};
    // 生成私钥
    privateKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, privateKeyData, 32);
    if (!privateKey)
    {
        // 处理错误，可能是私钥创建失败
        printf( "私钥创建失败\n");
        handleErrors();
    }

    // 生成公钥
    if (!X25519_algorithm(0, NULL, NULL, publicKey))
    {
        printf( "Failed to generate public key.\n");
    }

    // 生成共享密钥
    if (!X25519_algorithm(1, publicKey, privateKey, sharedSecret))
    {
        printf( "Failed to generate shared secret.\n");
    }

    // 清理资源
    EVP_PKEY_free(publicKey);
    EVP_PKEY_free(privateKey);
    EVP_PKEY_free(sharedSecret);
    printf("algo_25519_test end\n");
    return 0;
}
